package com.ninelock.config;

import com.ninelock.config.service.UserService;
import com.ninelock.properties.OAuth2ClientProperties;
import com.ninelock.properties.OAuth2Properties;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author wultn
 * @Description 认证服务
 * @Date 15:01 2020/4/30
 * @Param
 * @return
 **/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  @Autowired private OAuth2Properties oAuth2Properties;
  @Autowired private AuthenticationManager authenticationManager;
  @Autowired private UserService userDetailsService;

  @Autowired private RedisConnectionFactory redisConnectionFactory;

  @Autowired(required = false)
  private JwtAccessTokenConverter jwtAccessTokenConverter;

  @Autowired(required = false)
  private TokenEnhancer jwtTokenEnhancer;

  @Autowired private PasswordEncoder passwordEncoder;

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    // 扩展token返回结果
    if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
      TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
      List<TokenEnhancer> enhancerList = new ArrayList<>();
      enhancerList.add(jwtTokenEnhancer);
      enhancerList.add(jwtAccessTokenConverter);
      tokenEnhancerChain.setTokenEnhancers(enhancerList);
      // jwt
      endpoints.tokenEnhancer(tokenEnhancerChain).accessTokenConverter(jwtAccessTokenConverter);
    }
    endpoints
      .tokenStore(new RedisTokenStore(redisConnectionFactory))
      .authenticationManager(authenticationManager)
      .userDetailsService(userDetailsService);
  }
  /**
   * 配置客户端一些信息
   *
   * @param clients
   * @throws Exception
   */
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    InMemoryClientDetailsServiceBuilder build = clients.inMemory();
    if (ArrayUtils.isNotEmpty(oAuth2Properties.getClients())) {
      for (OAuth2ClientProperties config : oAuth2Properties.getClients()) {
        build
            .withClient(config.getClientId())
            .secret(passwordEncoder.encode(config.getClientSecret()))
            .accessTokenValiditySeconds(config.getAccessTokenValiditySeconds())
            .refreshTokenValiditySeconds(60 * 60 * 24 * 15)
            .authorizedGrantTypes("refresh_token", "password", "authorization_code")
            .scopes("all");
      }
    }
  }
  /**
   * springSecurity 授权表达式，
   *
   * @param security
   * @throws Exception
   */
  @Override
  public void configure(AuthorizationServerSecurityConfigurer security) {
    security.tokenKeyAccess("permitAll()");
    security.checkTokenAccess("isAuthenticated()");
  }
}
